﻿#include "stdafx.h"
#include "Becode.h"

#include "DebugAssert.h"

_NAMESPACE_BEGIN

BECode::BECode()
{
	index=0;
	pRoot=pFocus=NULL;
	fp=NULL;
}

void BECode::AddRef()
{
	refCount++;
}

void BECode::Release()
{
	if( --refCount == 0 )
		delete this;
}

bool BECode::Open( CONST_REF(wstring) filename,OPEN_TYPE type )
{			

	try
	{
		if(fp)
			Close();
		if(OPEN_TYPE_NEW==type)
		{
			_tfopen_s(&fp,filename.c_str(),_T("wb"));
		}
		else if(OPEN_TYPE_READWRITE==type)
		{
			_tfopen_s(&fp,filename.c_str(),_T("r+b"));
		}
		else if(OPEN_TYPE_READONLY==type)
		{
			_tfopen_s(&fp,filename.c_str(),_T("rb"));
		}

		if(NULL==fp)
		{
			throw("打开BECode文件失败");
		}

		this->filename=filename;
		this->openType=type;

		fseek(fp,0,SEEK_END);   
		fileSize=ftell(fp);
		fseek(fp,0,SEEK_SET);   


		if(OPEN_TYPE_READONLY==type)
		{
			ReadHierarchy(false);//只读，需要时才读入二进制缓冲数据
		}
		else if(OPEN_TYPE_READWRITE==type)
		{
			ReadHierarchy(true);//如果需要回写，则要载入全部二进制缓冲数据
		}
		else
		{

		}
		return true;
	}
#pragma warning(disable: 4101)
#pragma warning(push)
	catch (char* e)
	{
		if(fp) fclose(fp);
		SAVE_LOG("打开文件失败!");
		return false;
	}		
#pragma warning(pop)

}
bool BECode::GetSon(CONST_REF(string) name)
{
	assert(pFocus);
	for (std::vector<Node*>::iterator i=pFocus->sons.begin();i!=pFocus->sons.end();i++)
	{
		if((*i)->name==name)
		{
			pFocus=*i;
			return true;
		}
	}
	return false;
}

bool BECode::ToParent()
{
	assert(pFocus->pParent);
	pFocus=pFocus->pParent;
	return true;
}
bool BECode::GetSon( WORD index )
{
	assert(pFocus);
	assert(index<pFocus->sons.size());
	pFocus=pFocus->sons[index];
	return true;
}
bool BECode::GetLastSon()
{
	assert(pFocus);
	pFocus=pFocus->sons.back();
	return true;
}

void BECode::ReadHierarchy(bool loadbuffer)
{
	fseek(fp,0,SEEK_SET);//从头开始递归读取
	ReadNode(pRoot,loadbuffer);
	if(!pRoot)
		return;
	pFocus=pRoot;
	pRoot->pParent=pRoot;
}

void BECode::ReadNode( Node*& p,bool loadbuffer )
{
	DWORD pos=ftell(fp);
	if(pos>=fileSize)
		return;

	newobj(p,Node);

	//载入节点名称
	UCHAR namelen;
	fread((void*)&namelen,sizeof(namelen),1,fp);	
	p->name.resize(namelen);
	fread((void*)&p->name.at(0),sizeof(char),namelen,fp);	

	UCHAR type;
	fread((void*)&type,sizeof(type),1,fp);	
	p->type=(NODE_TYPE)type;

	if(NODE_TYPE_EMPTY==type)//空节点
	{
		p->ct=boost::any();
	}
	else if(BECODE_TYPE2ENUM(Buffer)==type)
	{
		UINT size;
		//因为缓冲数据比较大，所以需要的时候才载入,这里只记录下位置，跳过缓冲数据
		p->bufferFilePos=ftell(fp);
		fread((void*)&size,sizeof(size),1,fp);

		Buffer buffer;
		p->ct=boost::any(buffer);

		if(loadbuffer)
		{
			Buffer* pb=boost::any_cast<Buffer>(&p->ct);
			pb->SetSize(size);
			if(size>0)
				fread((void*)pb->GetBuffer(),sizeof(__byte),size,fp);
		}
		else
			fseek(fp,size,SEEK_CUR);
	}
	else if(BECODE_TYPE2ENUM(string)==type)
	{
		WORD size;//字符串的长度不能超过USHRT_MAX
		fread((void*)&size,sizeof(size),1,fp);
		string str;
		p->ct=boost::any(str);
		string* pb=boost::any_cast<string>(&p->ct);
		pb->resize(size);
		if(size>0)
			fread((void*)&pb->at(0),sizeof(char),size,fp);
	}
	else if(BECODE_TYPE2ENUM(wstring)==type)
	{
		WORD size;//字符串的长度不能超过USHRT_MAX
		fread((void*)&size,sizeof(size),1,fp);

		wstring str;
		p->ct=boost::any(str);
		wstring* pb=boost::any_cast<wstring>(&p->ct);
		pb->resize(size);
		if(size>0)
			fread((void*)&pb->at(0),sizeof(wchar_t),size,fp);
	}
#define BECODE_READ_FILE(T) else if(BECODE_TYPE2ENUM(T)==type){T obj;\
	fread((void*)&obj,sizeof(obj),1,fp);p->ct=boost::any(obj);}		

	BECODE_READ_FILE(bool)	BECODE_READ_FILE(char)		BECODE_READ_FILE(UCHAR)
		BECODE_READ_FILE(short)	BECODE_READ_FILE(USHORT)
		BECODE_READ_FILE(INT32)	BECODE_READ_FILE(UINT32)	BECODE_READ_FILE(float)
		BECODE_READ_FILE(INT64)	BECODE_READ_FILE(UINT64)	BECODE_READ_FILE(double)
else
assert(!"unexpect type!");

#undef BECODE_READ_FILE


	WORD sonnum;
	fread((void*)&sonnum,sizeof(sonnum),1,fp);
	for (WORD i=0;i<sonnum;i++)
	{
		Node* pson=NULL;
		ReadNode(pson,loadbuffer);
		if(pson)
		{
			p->AddSon(pson);
		}
	}



}
void BECode::SaveNode(Node*p)
{
	UCHAR namelen=p->name.size();
	fwrite((void*)&namelen,sizeof(namelen),1,fp);
	fwrite((void*)p->name.c_str(),sizeof(char),namelen,fp);

	UCHAR type=p->type;
	fwrite((void*)&type,sizeof(type),1,fp);

	if(NODE_TYPE_EMPTY==p->type)
	{}
	else if(BECODE_TYPE2ENUM(Buffer)==p->type)
	{
		Buffer* pb=boost::any_cast<Buffer>(&p->ct);
		UINT size=pb->GetSize();
		fwrite((void*)&size,sizeof(size),1,fp);
		if(size>0)
			fwrite((void*)pb->GetBuffer(),sizeof(__byte),size,fp);
	}
	else if(BECODE_TYPE2ENUM(string)==p->type)
	{
		string* pb=boost::any_cast<string>(&p->ct);
		assert(pb->size()<USHRT_MAX);
		WORD size=pb->size();//字符串的长度不能超过USHRT_MAX
		fwrite((void*)&size,sizeof(size),1,fp);
		if(size>0)
			fwrite((void*)pb->c_str(),sizeof(char),size,fp);
	}
	else if(BECODE_TYPE2ENUM(wstring)==p->type)
	{
		wstring* pb=boost::any_cast<wstring>(&p->ct);
		assert(pb->size()<USHRT_MAX);
		WORD size=pb->size();//字符串的长度不能超过USHRT_MAX
		fwrite((void*)&size,sizeof(size),1,fp);
		if(size>0)
			fwrite((void*)pb->c_str(),sizeof(wchar_t),size,fp);
	}
#define BECOE_WRITE_FILE(T)	else if (BECODE_TYPE2ENUM(T)==p->type){\
	fwrite((void*)boost::any_cast<T>(&p->ct),sizeof(T),1,fp);}

	BECOE_WRITE_FILE(bool)	BECOE_WRITE_FILE(char)		BECOE_WRITE_FILE(UCHAR)
		BECOE_WRITE_FILE(short)	BECOE_WRITE_FILE(USHORT)
		BECOE_WRITE_FILE(INT32)	BECOE_WRITE_FILE(UINT32)	BECOE_WRITE_FILE(float)
		BECOE_WRITE_FILE(INT64)	BECOE_WRITE_FILE(UINT64)	BECOE_WRITE_FILE(double)
else
assert(!"unexpect type!");

#undef BECOE_WRITE_FILE
	WORD sonsnum=p->sons.size();
	fwrite((void*)&sonsnum,sizeof(sonsnum),1,fp);

	for (std::vector<Node*>::iterator i=p->sons.begin();i!=p->sons.end();i++)
	{
		SaveNode(*i);
	}
}

void BECode::Save( CONST_REF(wstring) name)
{
	if(!filename.empty())
	{
		if(this->filename!=filename && !this->filename.empty())//先关闭原来的文件
			Close();
		this->filename=filename;
		Open(filename.c_str(),OPEN_TYPE_NEW);//写入新文件
	}
	else
	{
		assert(!this->filename.empty());
		if(!fp)
			Open(this->filename.c_str(),OPEN_TYPE_NEW);//如果还没有打开文件，临时打开
	}
	assert(OPEN_TYPE_READONLY!=openType);
	fseek(fp,0,SEEK_SET);//从头开始递归写入
	if(pRoot)
		SaveNode(pRoot);
}
void BECode::ClearAll()
{
	delmem(pRoot);
	pFocus=NULL;
}

BECode::Node* BECode::AddNode( CONST_REF(string) npath )
{
	if(pFocus)
	{
		assert(pRoot);

		string::size_type lastpos=0;
		string::size_type pos;

		Node* pNode=pFocus;
		do 
		{
			pos=npath.find("/",lastpos);
			if(string::npos==pos)
			{
				pos=min(string::npos,npath.size());
			}
			string name=npath.substr(lastpos,pos-lastpos);
			if(name.empty())
			{
				pFocus=pRoot;
			}
			else
			{
				//if(!GetSon(name))//可以存在同名节点						
				{
					Node* p;
					newobj(p,Node);		
					p->name=name;
					pFocus->AddSon(p);
					GetLastSon();
				}
			}
			lastpos=pos+1;
		} while(lastpos<npath.size());			
	}
	else
	{
		assert(!pRoot);
		newobj(pRoot,Node);
		pRoot->name=npath;
		pFocus=pRoot;
		pRoot->pParent=pRoot;
	}
	return pFocus;

}

bool BECode::AddNode( CONST_REF(string) name,Buffer& obj )
{
	pFocus=AddNode(name);
	Write(obj);
	pFocus=pFocus->pParent;
	return true;
}

bool BECode::AddNode( CONST_REF(string) name,__byte* p,DWORD len )
{
	pFocus=AddNode(name);
	Write(p,len);
	pFocus=pFocus->pParent;
	return true;
}
void BECode::Write( Buffer& obj )
{
	if(pFocus->ct.type()==typeid(Buffer))
	{
		Buffer* pb=boost::any_cast<Buffer>(&pFocus->ct);
		pb->Clear();
	}
	pFocus->type=BECODE_TYPE2ENUM(Buffer);
	Buffer buffer;
	pFocus->ct=boost::any(buffer);
	*boost::any_cast<Buffer>(&pFocus->ct)=obj;
	//obj.CopyTo(*boost::any_cast<Buffer>(&pFocus->ct));		
}

void BECode::Read( Buffer*& obj )
{
	obj=boost::any_cast<Buffer>(&pFocus->ct);
	if(obj->GetSize()<=0)
	{
		UINT pos=ftell(fp);
		fseek(fp,pFocus->bufferFilePos,SEEK_SET);
		UINT size;
		fread((void*)&size,sizeof(size),1,fp);
		obj->SetSize(size);
		fread((void*)obj->GetBuffer(),sizeof(__byte),size,fp);
	}		
}

void BECode::Read( __byte* p,UINT& len )
{
	Buffer* pb;
	Read(pb);
	memcpy(p,pb->GetBuffer(),pb->GetSize());
	len=pb->GetSize();
}
void BECode::Close()
{
	if(fp)
		fclose(fp);
}

bool BECode::FindNode( CONST_REF(string) npath,bool report )
{
	if(!GetRootNodePtr())
		return false;
	string::size_type lastpos=0;
	string::size_type pos;

	Node* pNode=pFocus;
	do 
	{
		pos=npath.find("/",lastpos);
		if(string::npos==pos)
			pos=min(string::npos,npath.size());
		string name=npath.substr(lastpos,pos-lastpos);
		if(name.empty())
		{
			pFocus=pRoot;
		}
		else
		{
			if(!GetSon(name))
				goto failure;
		}
		lastpos=pos+1;
	} while(lastpos<npath.size());

	return true;

failure:
	if(report)
	{
		assert(!"cant find npath node");
	}
	pFocus=pNode;//查找失败，恢复pFocus指针
	return false;
}

bool BECode::DelNode( bool delsons/*=false*/ )
{
	if( !delsons && !pFocus->sons.empty())//还有子节点，且参数指定不可删除
		return false;
	if(pFocus->pParent==pFocus)//已经是根节点
		return false;
	Node* p=pFocus;
	pFocus=pFocus->pParent;
	pFocus->DelSon(p);
	return true;
}

void BECode::ReadConfigFile( const TCHAR* filename/*=NULL*/ )
{
	if(filename)
		Open(filename,OPEN_TYPE_READONLY);
	else 
		Open(L"bxlconfig.becode",OPEN_TYPE_READONLY);

	pStructTypeRoot=pRoot;		

	//WORD len;//结构体的字节数
	WORD sonnum=GetSonNum();
	for (WORD i=0;i<sonnum;i++)
	{
		GetSon(i);
		structName2Index[GetNodeName()]=i;//便于实用时查找到对应的定义		

		ToParent();
	}

	pRoot=NULL;//避免节点在配置文件关闭后被释放
	Close();
}

WORD BECode::GetSonNum()
{
	return pFocus->sons.size();
}
//////////////////////////////////////////////////////////////////////////
BECode::Node::Node()
{
	type=NODE_TYPE_EMPTY;
	pParent=NULL;
	bufferFilePos=0;
	structTypeId=0;
}
BECode::Node::~Node()
{
	for (std::vector<Node*>::iterator i=sons.begin();i!=sons.end();i++)
	{
		delmem(*i);
	}
}
void BECode::Node::DelSon( Node* p )
{
	for (std::vector<Node*>::iterator i=sons.begin();i!=sons.end();i++)
	{
		if(*i==p)
		{
			sons.erase(i);
			delmem(p);
			return;
		}
	}
	assert(!"cant find son to delete");
}

#undef BECODE_TYPE2ENUM

_NAMESPACE_END